package com.ra.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.ra.mapper.ArticleMapper;
import com.ra.mapper.ArticleTagMapper;
import com.ra.mapper.CategoryMapper;
import com.ra.pojo.*;
import com.ra.pojo.dto.*;
import com.ra.service.IArticleService;
import com.ra.service.IArticleTagService;
import com.ra.service.ITagService;
import com.ra.service.SearchService;
import com.ra.utils.BeanCopyUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Author : 今晚几点睡_Ada
 * Date: 2023/3/13
 * Time: 11:57
 * 注:
 */
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements IArticleService {

    @Autowired
    private IArticleTagService articleTagService;

    @Autowired
    private ArticleMapper articleMapper;
    @Autowired
    private ArticleTagMapper articleTagMapper;
    @Autowired
    private ITagService tagService;
    @Autowired
    private CategoryMapper categoryMapper;
    @Autowired
    private SearchService searchService;

    /**
     * 处理标签
     *
     * @param articleDTO
     * @return category
     */
    private Category saveArticleCategory(ArticleDTO articleDTO) {
        Category category = categoryMapper.selectOne(new LambdaQueryWrapper<Category>()
                .eq(Category::getCategoryName, articleDTO.getCategoryName()));
        //没有查询到分类并且文章不为草稿则插入新的分类
        if (Objects.isNull(category) && !articleDTO.getStatus().equals(3)) {
            category = Category.builder()
                    .categoryName(articleDTO.getCategoryName())
                    .build();
            categoryMapper.insert(category);
        }
        return category;
    }
    /**
     * 处理文章标签  (文章可以有多个标签)
     *
     * @param articleDTO 前台传递的数据
     * @param articleId  文章id
     */
    private void saveArticleTag(ArticleDTO articleDTO, Integer articleId) {
        //先判断是更新还是发布 不为空则为更新文章
        if (Objects.nonNull(articleDTO.getId())) {
            //先删除原有的tag
            articleTagMapper.delete(new LambdaQueryWrapper<ArticleTag>().eq(ArticleTag::getArticleId, articleDTO.getId()));
        }

        //在处理articleDTO传入的tag
        List<String> tagNameByDTO = articleDTO.getTagNames();
        //如果tagName不为空
        if (!tagNameByDTO.isEmpty()) {
            //查出数据库所有tag
            List<Tag> tags = tagService.list(new LambdaQueryWrapper<Tag>().in(Tag::getTagName, tagNameByDTO));
            System.out.println("tags = " + tags);
            //转String
            List<String> Tags = tags.stream().map(Tag::getTagName).collect(Collectors.toList());
            //前端传入的tag移除数据库中有的 得到需要添加到数据库的标签
            tagNameByDTO.removeAll(Tags);
            List<Integer> TagIds = tags.stream()
                    .map(Tag::getId)
                    .collect(Collectors.toList());
            System.out.println("数据库中标签id = " + TagIds);
            //移除之后如果不为空
            if (!tagNameByDTO.isEmpty()) {
                //将一个字符串类型的List对象tagNames，通过Stream的map方法，
                // 将每个字符串转换成一个Tag类型的对象
                // ，并将这些Tag对象收集到一个List中。
                List<Tag> tagList = tagNameByDTO.stream().map(item -> Tag.builder()
                        .tagName(item)
                        .build())
                        .collect(Collectors.toList());
                //在MP框架中，saveBatch()方法是IService类提供的一种批量插入数据的方法。51cto.com
                // 这个方法可以将要执行的数据分成N份，并且每份1000条，每满1000条就会执行一次批量插入，
                // 因此，性能要比循环单次插入的性能高很多。zhuanlan.zhihu.com
                //
                //在Java中，saveBatch()方法是Mybatis-plus提供的批量插入方法。
                // 当需要同时插入很多条数据时，可以使用该方法，可以有效地减少与数据库的交互次数，
                // 从而提高性能。51cto.com
                tagService.saveBatch(tagList);
                System.out.println("tagList = " + tagList);
                //提交成功之后即可拿到提交之后的属性
                List<Integer> tagIds = tagList.stream()
                        .map(Tag::getId)
                        .collect(Collectors.toList());
                System.out.println("tagIds = " + tagIds);
                TagIds.addAll(tagIds);

            }
            System.out.println("TagIds = " + TagIds);
            List<ArticleTag> articleTags = TagIds.stream().map(item -> ArticleTag.builder()
                    .articleId(articleId)
                    .tagId(item)
                    .build())
                    .collect(Collectors.toList());
            System.out.println("articleTags = " + articleTags);
            articleTagService.saveBatch(articleTags);
            //  int num = 10/0;
        }
    }
    /**
     * 发布或者更新文章
     *
     * @param articleDTO 前台传入的数据
     */
    @Override
    @Transactional//添加事务
    public void saveOrUpdateArticle(ArticleDTO articleDTO) {
        //文章分类 （文章只能拥有一个分类）
        Category category = saveArticleCategory(articleDTO);
        System.out.println("category = " + category);
        //数据传递转实体类
        Article article = BeanCopyUtil.copyObject(articleDTO, Article.class);
        //完善article属性
        UserDetailsDTO userDetailsDTO = (UserDetailsDTO) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        article.setUserId(userDetailsDTO.getUserInfoId());
        //文章分类不为空 则插入id到 article对象
        if (Objects.nonNull(category)) {
            article.setCategoryId(category.getId());
        }
        //提交文章
        saveOrUpdate(article);
        System.out.println("article = " + article);
        //提交成功之后即可拿到提交之后的属性
        saveArticleTag(articleDTO, article.getId());
    }

    /**
     * 分页查询文章
     * @param conditionDTO 文章查询条件
     * @return
     */
    @Override
    public RespPageBean<ArticleAdminDTO> listArticlesAdmin(ConditionDTO conditionDTO) {
        System.out.println("conditionDTO = " + conditionDTO);
        //数据
        List<ArticleAdminDTO> articleAdminDTOS = articleMapper.listArticlesAdminByPage(conditionDTO);

        //条数
       Long current= articleMapper.queryArticlesAdminCurrentByPage(conditionDTO);
        return new RespPageBean<>(current,articleAdminDTOS);
    }

    @Override
    public List<ArticleSearchDTO> listArticlesBySearch(ConditionDTO condition) {
        return searchService.searchArticle(condition.getKeywords());
    }


}
